# @Time : 2021/4/7 9:05
# @Author : Fioman 
# @Phone : 13149920693
"""
程序入口主函数,主要负责主程序的启动
"""
import bottle
import bottle.ext.websocket as wbs
import json
import gevent
import settings
import os

from app.line_camera_cal_tool import LineCameraCalTool
from app.state_listener import StatesListener
from app.states import DeviceStates
from app.produce_handler import ProduceHandler
from app.line_camera_joint_tool import ImageJointTool
from app.cbj_zmc_tool import CbjTool
from app.cutter_camera_cal_tool import CutterCamCal
from app.logger_tool import LoggerTool
from program_start_check import ps_contral
from eel import eel_manager
from tools.hd_logger import HdLogger
from tools.config_params import ConfigParams
from db_tools.db_handler import DbHandler
from drivers.offline_zmc import OfflineZmc
from drivers.cam_zmc import CamZmc
from drivers.cutter_zmc import CutterZmc
from drivers.cbj_zmc import CbjZmc
from drivers.line_camera import LineCamera
from drivers.area_camera import AreaCamera
from tools.websocket_queue import WebSocketQueue
from eap_socket.hd_client import HdClient


# from hd_socket.eap_socket_handler import HdClient


@bottle.route('/<path:path>')
def _static(path):
    return bottle.static_file(path, root=settings.WEB_PATH)


@bottle.get('/eel', apply=[wbs.websocket])
def _websocket(ws):
    global websockets
    page = bottle.request.query.page
    websockets += [(page, ws)]

    while True:
        msg = ws.receive()
        print("recv msg: ", msg)
        if msg is not None:
            message = json.loads(msg)
            gevent.spawn(_process_message, message)
        else:
            print("websockets = {}".format(websockets))
            websockets.remove((page, ws))
            break
    _websocket_close()


def _websocket_close():
    """
    页面关闭的时候,也就是程序关闭的时候,要做的收尾的工作.
    :return:
    """
    gevent.sleep(1)
    debugMsg = "页面websocket关闭,程序退出,关闭之后的len(websockets) = {},websockets = {}".format(len(websockets), websockets)
    print(debugMsg)
    logger.debug(debugMsg)
    _program_stop()
    os._exit(1)


def _program_stop():
    """
    程序页面关闭要做的事情
    :return:
    """
    cutterZmc.cutter_zmc_stop()
    ph.workingStopFlag = True
    settings.IS_MAIN_ALIVE = False
    db.update_login_state(False)


def _process_message(message):
    """
    解析前端发送过来的消息,并返回.
    :param message:前端发送过来的消息内容
    :return:
    """
    if 'call' in message:
        obj_name = message.get('obj_name', False)
        fun_name = message.get('fun_name', False)
        if obj_name and fun_name:
            if obj_name == 'global':
                if globals().get(fun_name):
                    try:
                        return_val = globals()[fun_name](*message['args'])
                    except Exception as e:
                        return_val = "Call error!\n" + str(e)
                else:
                    return_val = "Call error!Global does not have %s function!" % fun_name
            else:
                if globals().get(obj_name):
                    if fun_name in dir(globals()[obj_name]):
                        if hasattr(getattr(globals()[obj_name], fun_name), '__call__'):
                            try:
                                return_val = getattr(globals()[obj_name], fun_name)(*message['args'])
                            except Exception as e:
                                return_val = "Call error!\n" + str(e)
                        else:
                            return_val = "Call error!%s 's %s is not a function!" % (obj_name, fun_name)
                            print(return_val)
                            logger.debug(return_val)
                    else:
                        return_val = "Call error!%s does not have this %s!" % (obj_name, fun_name)
                        print(return_val)
                        logger.debug(return_val)
                else:
                    return_val = "Call error!Global does not have %s object!" % obj_name
                    print(return_val)
                    logger.debug(return_val)
        else:
            return_val = "Call command syntax error!"
            print(return_val)
            logger.debug(return_val)
        eel_manager.repeat_send(json.dumps({'return': message['call'], 'value': return_val}), websockets)
    else:
        print('Invalid message received: ', message)
        logger.debug("Invalid message received: ", message)


if __name__ == '__main__':
    msgQueue = WebSocketQueue().websocketQueue
    websockets = []  # 存放websocket的套接字
    if not settings.DEVELOP:
        # 验证设备,如果不是原厂和自己的设备,程序就不启动
        # ps_contral.verify_device() 先不验证这个
        # 查看进程,如果程序中已经存在了进程,就通知用户结束进程
        ps_contral.check_exe()
    settings.IS_MAIN_ALIVE = True
    # 设备的信息初始化.
    logger = HdLogger()
    db = DbHandler()
    cp = ConfigParams()
    offlineZmc = OfflineZmc()
    line_cam1, line_cam2, cutCam1, cutCam2 = db.get_cam_IP_connect_by_camName()
    camZmc = CamZmc()
    cbjZmc = CbjZmc()
    cutterZmc = CutterZmc()
    leftCam = LineCamera(line_cam1[0], line_cam1[1])  # 左相机
    rightCam = LineCamera(line_cam2[0], line_cam2[1])  # 右相机
    cutterCam1 = AreaCamera(cutCam1[0], cutCam1[1])  # 铡刀一号相机
    cutterCam2 = AreaCamera(cutCam2[0], cutCam2[1])  # 铡刀二号相机
    deviceStates = DeviceStates()
    imageJoint = ImageJointTool(leftCam, rightCam, camZmc)  # 相机拼接工具
    lineCamCal = LineCameraCalTool(imageJoint, cbjZmc, cutterZmc)  # 相机标定工具
    cutterCamCal = CutterCamCal(cutterCam1, cutterCam2, cutterZmc)
    ph = ProduceHandler(imageJoint, cutterCamCal, camZmc, cbjZmc, cutterZmc, deviceStates, offlineZmc)
    cbjTool = CbjTool(cbjZmc)
    hdlt = LoggerTool()
    #
    es = HdClient()
    es.managerThread.setDaemon(True)
    es.managerThread.start()
    stateListener = StatesListener(leftCam=leftCam, rightCam=rightCam, cutterCam1=cutterCam1, cutterCam2=cutterCam2, offlineZmc=offlineZmc,
                                   camZmc=camZmc, cbjZmc=cbjZmc, cutterZmc=cutterZmc, deviceStates=deviceStates)
    stateListener.managerThread.setDaemon(True)
    stateListener.managerThread.start()
    print("初始化完成,开始启动界面服务器...")
    logger.debug("Program start")
    res = db.web_request_dump_data_base()
    logger.debug("数据库自动备份：{}".format(res))
    eel_manager.start_eel()
    eel_manager.send_loop(msgQueue, websockets)

